'''
Created on Sep 27, 2013

@author: dewey
'''

from PyQt4.QtCore import *
from PyQt4.QtGui import *

import externalreslib.nts as nts
import tempfile
import zipfile
import urllib
import os

from .tiles import TiledBitmapLayer, TileFetcherManager, validImage
from qpynygeolib.maplayers import LayerFactory, BitmapLayer

class ToporamaLayerFactory(LayerFactory):
    
    def __init__(self):
        super(ToporamaLayerFactory, self).__init__()
        self.__types = ("MapFrameLayer|BitmapLayer|TiledBitmapLayer|NTSTileLayer",)
    
    def layerTypes(self):
        out = list(self.__types)
        self.appendChildFactoryLayerTypes(out)
        return out
    
    def newLayer(self, layerType, layerId, options={}):
        if layerType == self.__types[0]:
            return NTSTileLayer(layerId)
        else:
            return self.newLayerFromChildFactory(layerType, layerId, options)

class NTSTileLayer(TiledBitmapLayer):    
    
    ZOOM_50K_FULLSIZE = 3
    ZOOM_CUTOFF_DEFAULT = (7, 9.5, 11.3)
    
    def __init__(self, layerId, cacheDir=None, zIndex=0):
        super(NTSTileLayer, self).__init__(layerId, "toporama", cacheDir, zIndex)
        self.__zoomCutoff = self.ZOOM_CUTOFF_DEFAULT
 
    def type(self):
        return "MapFrameLayer|BitmapLayer|TiledBitmapLayer|NTSTileLayer"
    
    def scaleFromZoom(self, zoom):
        if zoom >= self.ZOOM_50K_FULLSIZE:
            return nts.SCALE_50K
        else:
            return zoom
    
    def zoomCutoff(self):
        return self.__zoomCutoff
    
    def setZoomCutoff(self, cutoffVals):
        self.__zoomCutoff = cutoffVals
    
    def downloadTiles(self, force=False, tileZoom=None):
        if tileZoom <= nts.SCALE_250K:
            return False
        elif tileZoom == nts.SCALE_50K:
            return TiledBitmapLayer.downloadTiles(self, force, tileZoom)
        else:
            return force
            
    def tileManagerThread(self, tileList, force):
        return ToporamaTileManagerThread(self, tileList, force)
    
    def getTiles(self, bounds, zoom):
        scale = self.scaleFromZoom(zoom)

        ntsTiles = nts.tilesByBounds(scale, bounds)
        zoomTiles = []
        for tile in ntsTiles:
            zoomTiles.append(tile + (zoom,))
        return zoomTiles
    
    def randomTileUrl(self, tile):
        zoom = tile[2]
        scale = self.scaleFromZoom(zoom)
        ntsId = nts.ntsId(scale, tile)
        squished = "".join(ntsId).lower()
        if zoom == nts.SCALE_50K:
            return "http://ftp2.cits.rncan.gc.ca/pub/toporama/50k/images/toporama_%s.jpg" % squished
        elif zoom == self.ZOOM_50K_FULLSIZE:
            return "http://ftp2.cits.nrcan.gc.ca/pub/toporama/50k_geo_tif/%s/%s/toporama_%s_geo.zip" % (ntsId[0], ntsId[1].lower(), squished)
        else:
            return None

    def setVisible(self, flag):
        BitmapLayer.setVisible(self, flag)

    def fileName(self, tile):
        zoom = tile[2]
        scale = self.scaleFromZoom(zoom)
        stringId = "".join(nts.ntsId(scale, tile)).lower()
        if zoom >= self.ZOOM_50K_FULLSIZE:
            return "toporama_full_%s.jpg" % stringId
        else:
            return "toporama_%s.jpg" % stringId
        
    def tileZoomFromMapZoom(self, mapZoom):
        if mapZoom <= self.zoomCutoff()[0]:
            return nts.SCALE_SERIES
        elif mapZoom <= self.zoomCutoff()[1]:
            return nts.SCALE_250K
        elif mapZoom <= self.zoomCutoff()[2]:
            return nts.SCALE_50K
        else:
            return self.ZOOM_50K_FULLSIZE
    
    def tileBounds(self, tile):
        return nts.tileBounds(self.scaleFromZoom(tile[2]), tile)
    def minZoom(self):
        return nts.SCALE_SERIES
    def maxZoom(self):
        return self.ZOOM_50K_FULLSIZE
    def pauseAfterDownload(self):
        return 50


class ToporamaTileManagerThread(TileFetcherManager):
    
    def __init__(self, layer, tileList, force, loadOnFinish=True):
        super(ToporamaTileManagerThread, self).__init__(layer, tileList, force, loadOnFinish)
    
    def load(self, url, imageFile, tile):
        isZip = url is not None and url.endswith(".zip")
        if isZip:   
            downloadFile = tempfile.mkstemp()[1]
        else:
            downloadFile = imageFile
        if not downloadFile in TileFetcherManager.fileLocks:
            TileFetcherManager.fileLocks.add(downloadFile)
            image = None
        
            if os.path.isfile(imageFile):
                image = QImage(imageFile)
            
            downloaded = False
            if not validImage(image) and self.layer().downloadTiles(self.force(), tile[2]) and url is not None:
                try:    
                    if urllib.urlretrieve(url, downloadFile):
                        if isZip:
                            print url
                            image = self.huntForTifInZip(downloadFile, imageFile)
                            os.remove(downloadFile)
                        else:
                            image = QImage(imageFile)
                    else:
                        raise IOError
                except IOError, e:
                    print "IO ERROR", e
                    self.emit(SIGNAL("error(QString)"), QString(url))
                downloaded = True
            if image is not None and self.loadOnFinish:
                if validImage(image) and not self.isCancelled():
                    self.emit(SIGNAL("imageDownloaded(QImage, int, int, int)"), image, tile[0], tile[1], tile[2])
            TileFetcherManager.fileLocks.remove(downloadFile)
            if self.layer().pauseAfterDownload() > 0 and downloaded:
                self.usleep(self.layer().pauseAfterDownload())
    
    def huntForTifInZip(self, filepath, destinationJpg):
        zipF = zipfile.ZipFile(filepath)
        for name in zipF.namelist():
            if name.endswith(".tif"):
                newImage = zipF.extract(name, self.layer().cacheDir)
                image = QImage(newImage)
                image.save(destinationJpg)
                os.remove(newImage)
                return image
        return None
    